package pers.cz.javacvdemo.oss.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import pers.cz.javacvdemo.oss.config.FileProperties;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.model.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.time.Duration;
import java.util.Collection;
import java.util.List;

/**
 * @version 1.0
 * @description: S3同步客户端模板实现
 * @author: ChengZhi 0336
 * @create: 2025-08-13 14:51
 **/
@Slf4j
@RequiredArgsConstructor
public class OssTemplate implements FileTemplate {

	private final FileProperties fileProperties;
	private final ObjectMapper objectMapper = new ObjectMapper();

	private S3Client s3Client;

	@Override
	public void createBucket(String bucketName) {
		try {
			CreateBucketRequest createBucketRequest = CreateBucketRequest.builder()
					.bucket(bucketName)
					.build();

			CreateBucketResponse response = s3Client.createBucket(createBucketRequest);
			log.info("成功创建桶: {}, 响应: {}", bucketName, response);
		} catch (S3Exception e) {
			log.error("创建桶失败: {}, 错误: {}", bucketName, e.getMessage());
			throw new RuntimeException("创建桶失败: " + bucketName, e);
		}
	}

	@Override
	public List<Bucket> getAllBuckets() {
		try {
			ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder().build();
			ListBucketsResponse response = s3Client.listBuckets(listBucketsRequest);
			log.info("成功获取所有桶，数量: {}", response.buckets().size());
			return response.buckets();
		} catch (S3Exception e) {
			log.error("获取所有桶失败，错误: {}", e.getMessage());
			throw new RuntimeException("获取所有桶失败", e);
		}
	}

	@Override
	public void removeBucket(String bucketName) {
		try {
			DeleteBucketRequest deleteBucketRequest = DeleteBucketRequest.builder()
					.bucket(bucketName)
					.build();

			DeleteBucketResponse response = s3Client.deleteBucket(deleteBucketRequest);
			log.info("成功删除桶: {}, 响应: {}", bucketName, response);
		} catch (S3Exception e) {
			log.error("删除桶失败: {}, 错误: {}", bucketName, e.getMessage());
			throw new RuntimeException("删除桶失败: " + bucketName, e);
		}
	}

	@Override
	public void putObject(String bucketName, String objectName, InputStream stream, String contextType) throws Exception {
		try {
			PutObjectRequest putObjectRequest = PutObjectRequest.builder()
					.bucket(bucketName)
					.key(objectName)
					.contentType(contextType)
					.build();

			PutObjectResponse response = s3Client.putObject(putObjectRequest, software.amazon.awssdk.core.sync.RequestBody.fromBytes(stream.readAllBytes()));

			log.info("成功上传对象: {}/{}, 响应: {}", bucketName, objectName, response);
		} catch (S3Exception e) {
			log.error("上传对象失败: {}/{}, 错误: {}", bucketName, objectName, e.getMessage());
			throw new RuntimeException("上传对象失败: " + bucketName + "/" + objectName, e);
		}
	}

	@Override
	public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
		// 调用带contentType的方法，使用默认的contentType
		putObject(bucketName, objectName, stream, "application/octet-stream");
	}

	public void putFilesAndDeleteSource(String bucketName, Collection<File> files) {
		files.forEach(file -> {
			boolean success = false;
			try {
				putObject(bucketName, file.getName(), new FileInputStream(file));
				success = true;
			} catch (Exception e) {
				throw new RuntimeException(e);
			} finally {
				if (success) {
					file.delete();
				}
			}
		});
	}

	@Override
	public void putObject(Serializable serializable, String fileName) {
		try {
			// 将对象序列化为JSON字符串
			String jsonString = objectMapper.writeValueAsString(serializable);
			byte[] jsonBytes = jsonString.getBytes("UTF-8");

			PutObjectRequest putObjectRequest = PutObjectRequest.builder()
					.bucket(fileProperties.getBucketName())
					.key(fileName)
					.contentType("application/json")
					.build();

			PutObjectResponse response = s3Client.putObject(putObjectRequest,
					software.amazon.awssdk.core.sync.RequestBody.fromBytes(jsonBytes));

			log.info("成功上传序列化对象: {}, 响应: {}", fileName, response);
		} catch (Exception e) {
			log.error("上传序列化对象失败: {}, 错误: {}", fileName, e.getMessage());
			throw new RuntimeException("上传序列化对象失败: " + fileName, e);
		}
	}

	@Override
	public <T> T getObject(String fileName, Class<T> clazz) {
		try {
			GetObjectRequest getObjectRequest = GetObjectRequest.builder()
					.bucket(fileProperties.getBucketName())
					.key(fileName)
					.build();

			ResponseInputStream<GetObjectResponse> response = s3Client.getObject(getObjectRequest);

			// 将响应反序列化为对象
			T result = objectMapper.readValue(response, clazz);
			log.info("成功获取并反序列化对象: {}", fileName);
			return result;
		} catch (Exception e) {
			log.error("获取并反序列化对象失败: {}, 错误: {}", fileName, e.getMessage());
			throw new RuntimeException("获取并反序列化对象失败: " + fileName, e);
		}
	}

	public InputStream getObjectAsInputStream(String bucketName, String objectName) {
		try {
			GetObjectRequest getObjectRequest = GetObjectRequest.builder()
					.bucket(bucketName)
					.key(objectName)
					.build();

			ResponseInputStream<GetObjectResponse> response = s3Client.getObject(getObjectRequest);
			log.info("成功获取对象: {}/{}", bucketName, objectName);
			return response;
		} catch (S3Exception e) {
			log.error("获取对象失败: {}/{}, 错误: {}", bucketName, objectName, e.getMessage());
			throw new RuntimeException("获取对象失败: " + bucketName + "/" + objectName, e);
		}
	}

	@Override
	public void removeObject(String bucketName, String objectName) throws Exception {
		try {
			DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder()
					.bucket(bucketName)
					.key(objectName)
					.build();

			DeleteObjectResponse response = s3Client.deleteObject(deleteObjectRequest);
			log.info("成功删除对象: {}/{}, 响应: {}", bucketName, objectName, response);
		} catch (S3Exception e) {
			log.error("删除对象失败: {}/{}, 错误: {}", bucketName, objectName, e.getMessage());
			throw new RuntimeException("删除对象失败: " + bucketName + "/" + objectName, e);
		}
	}

	/**
	 * 初始化S3客户端
	 * @throws Exception
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		log.info("开始初始化S3客户端，配置: {}", fileProperties.getOss());

		s3Client = S3Client.builder()
				.region(Region.of(fileProperties.getOss().getRegion()))
				.endpointOverride(URI.create(fileProperties.getOss().getEndpoint()))
				.credentialsProvider(StaticCredentialsProvider.create(
						AwsBasicCredentials.create(fileProperties.getOss().getAccessKey(), fileProperties.getOss().getSecretKey())
				))
				.serviceConfiguration(S3Configuration.builder()
						.pathStyleAccessEnabled(true)
						.build())
				.httpClient(ApacheHttpClient.builder()
						.connectionTimeout(Duration.ofSeconds(30))
						.socketTimeout(Duration.ofSeconds(30))
						.build())
				.build();

		log.info("S3客户端初始化完成");
	}
}
